﻿using System;
using System.Collections.Generic;
using System.Data.Objects.DataClasses;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web.Mvc;
using Unijovem.Domain.Utils;

namespace Unijovem.UI.Models
{
    public class ModelBase 
    {
        public const string FormatoData = "dd/MM/yyyy";
        public int Id { get; set; }
        public bool Ativo { get; set; }
        public bool UsuarioEstaLogado;
    }

    public class ModelBase<T, TEntity> : ModelBase
        where T : new()
        where TEntity : GeneralAction, new()
    {
        public TEntity CriarDominio(TEntity dominio = default(TEntity))
        {
            if (dominio == null)
                dominio = new TEntity();

            foreach (var property in dominio.GetType().GetProperties().Where(p => !p.Name.Contains("Key") && !p.Name.EndsWith("Reference")))
            {
                var propertyModel = typeof(T).GetProperty(property.Name);

                if (propertyModel == null) continue;

                var valor = propertyModel.GetValue(this, null);

                if (property.PropertyType.Namespace.Contains("Domain"))
                {
                    if (valor == null) continue;

                    var method = propertyModel.PropertyType.GetMethod("CriarDominio");

                    if (method.IsGenericMethodDefinition)
                    {
                        var methodGeneric =
                            propertyModel.PropertyType.GetMethod("CriarDominio").MakeGenericMethod(new[]{property.PropertyType});
                        valor = methodGeneric.Invoke(valor, new[] {property.GetValue(dominio, null)});
                    }
                    else
                        valor = method.Invoke(valor, new[] { property.GetValue(dominio, null) });
                }

                property.SetValue(dominio, valor, null);
            }

            return dominio;
        }

        public IEnumerable<T> CriarViewModel(IEnumerable<EntityObject> dominio)
        {
            return dominio.Select(CriarViewModel).ToList();
        }

        public T CriarViewModel(EntityObject dominio)
        {
            if (dominio == null) return default(T);

            var model = new T();

            foreach (var property in model.GetType().GetProperties())
            {
                try
                {
                    var propertyDominio = dominio.GetType().GetProperty(property.Name);
                    if (propertyDominio == null) continue;
                    
                    var valorDominio = propertyDominio.GetValue(dominio, null);
                    if (valorDominio == null) continue;
                    
                    if (valorDominio.GetType().Namespace.Contains("Domain"))
                    {
                        var method = property.PropertyType.GetMethod("CriarViewModel", new[] { typeof(EntityObject) });
                        var retornoMetodo = method.Invoke(Activator.CreateInstance(property.PropertyType),
                                                          new[] { propertyDominio.GetValue(dominio, null) });
                        property.SetValue(model, retornoMetodo, null);
                    }
                    else if (valorDominio.GetType().FullName.Contains("EntityCollection"))
                    {
                        var listTipo = property.PropertyType.FullName.Split(new[] { '[', ']', ',' }, StringSplitOptions.RemoveEmptyEntries);
                        var tipo = Activator.CreateInstance(listTipo[2], listTipo[1]).Unwrap();
                        var method = tipo.GetType().GetMethod("CriarViewModel", new[] { typeof(List<EntityObject>) });
                        var retornoMetodo = method.Invoke(tipo, new[] { propertyDominio.GetValue(dominio, null) });
                        property.SetValue(model, retornoMetodo, null);
                    }
                    else
                        property.SetValue(model, propertyDominio.GetValue(dominio, null), null);
                }
                catch
                {
                    continue;
                }
            }

            return model;
        }

        public static T Converter(FormCollection collection)
        {
            var dominio = Activator.CreateInstance(typeof(T));

            foreach (string key in collection.Keys)
            {
                var propriedade = dominio.GetType().GetProperty(key);

                try
                {
                    if (propriedade != null)
                    {
                        if (propriedade.PropertyType == typeof(Decimal) ||
                            propriedade.PropertyType == typeof(decimal))
                            propriedade.SetValue(dominio, Decimal.Parse(collection[key]), null);
                        else if (propriedade.PropertyType == typeof(Boolean) ||
                                 propriedade.PropertyType == typeof(bool))
                            propriedade.SetValue(dominio, Boolean.Parse(collection[key].Split(',').First()), null);
                        else if (propriedade.PropertyType == typeof(Int16) ||
                                 propriedade.PropertyType == typeof(Int32) ||
                                 propriedade.PropertyType == typeof(Int64) ||
                                 propriedade.PropertyType == typeof(uint) ||
                                 propriedade.PropertyType == typeof(UInt16) ||
                                 propriedade.PropertyType == typeof(UInt32) ||
                                 propriedade.PropertyType == typeof(UInt64) ||
                                propriedade.PropertyType == typeof(int?))
                            propriedade.SetValue(dominio, int.Parse(collection[key]), null);
                        else if (propriedade.PropertyType == typeof(DateTime))
                            propriedade.SetValue(dominio, DateTime.Parse(collection[key]), null);
                        else if (propriedade.PropertyType == typeof(char))
                            propriedade.SetValue(dominio, char.Parse(collection[key]), null);
                        else
                            propriedade.SetValue(dominio, collection[key], null);
                    }
                }
                catch
                {
                }
            }

            return (T)dominio;
        }

        public string GetParameterValue(string url, string paramName)
        {
            var uri = new Uri(url);
            if (!string.IsNullOrEmpty(uri.Query) && uri.Query.ToLower().Contains(paramName))
            {
                Match m = Regex.Match(uri.Query, "^?" + paramName + "=([^&#]*)");
                if (m.Success) return m.Value.Replace(paramName + "=", string.Empty);
            }
            return string.Empty;
        }
    }
}